package cn.itsource.service.impl;

import cn.itsource.cache.ICourseTypeCache;
import cn.itsource.client.PageConfigClient;
import cn.itsource.client.PageConfigClientFallbackFactory;
import cn.itsource.client.RedisClient;
import cn.itsource.domain.CourseType;
import cn.itsource.mapper.CourseTypeMapper;
import cn.itsource.service.ICourseTypeService;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.Serializable;
import java.util.*;

/**
 * <p>
 * 课程目录 服务实现类
 * </p>
 *
 * @author yhptest
 * @since 2020-02-17
 */
@Service
public class CourseTypeServiceImpl extends ServiceImpl<CourseTypeMapper, CourseType> implements ICourseTypeService {

    @Autowired
    private CourseTypeMapper courseTypeMapper;

    //和mapper差不多，mapper操作的是数据库的数据，而换成操作的是redis数据
    @Autowired
    private ICourseTypeCache courseTypeCache;

    @Autowired
    private PageConfigClient pageConfigClient;

    @Autowired
    private RedisClient redisClient;

    @Override
    public void staticIndexPageInit() {

        //1页面名称写死，约定大于配置
        String pageName = "CourseSiteIndex";

        //2 需要一个保存到redis数据库的key
        String dataKey="CourseSiteIndex_data";
        //本来就是从redis获取，还要在放一次，其他页面静态化的场景不一定有缓冲
        List<CourseType> courseTypes = this.treeData(0L);
        //课程
        Map<String,Object> courseTypeSdata = new HashMap<>();
        courseTypeSdata.put("courseTypes",courseTypes);
        //职位
        //Map<String,Object> JobsTypeSdata = new HashMap<>();
        //JobsTypeSdata.put("jobTypes",courseTypes);
        redisClient.add(dataKey, JSONArray.toJSONString(courseTypeSdata)); //{courseTypes:[]}

        //3 调用方法模板+数据=静态页面
        pageConfigClient.staticPage(pageName,dataKey);
    }

    @Override
    public List<Map<String, Object>> queryCrumbs(Long courseTypeId) {
        List<Map<String,Object>> result = new ArrayList<>();
        //1 通过courseTypeId获取CourseType，从而得到path，就能得到层次结构 .1.2.3. List
        String path = courseTypeMapper.selectById(courseTypeId).getPath(); //.1.2.3.
        path = path.substring(1,path.length()-1); // 1.2.3
        System.out.println(path);
        String[] paths = path.split("\\."); //[1,2,3]
        //2 对每个节点进行处理 Map
        for (String idStr : paths) {
            Map<String,Object> node = new HashMap<>();
            //2.1 自己
            CourseType owerCourseType = courseTypeMapper.selectById(Long.valueOf(idStr));
            node.put("ownerCourseType",owerCourseType);
            //2.2 兄弟
            //2.1.1 获取父亲的所有儿子
            Long pid = owerCourseType.getPid();
            List<CourseType> allChirdren = courseTypeMapper
                    .selectList(new EntityWrapper<CourseType>().eq("pid", pid));
            //2.1.2 删除自己
            Iterator<CourseType> iterator = allChirdren.iterator();
            while (iterator.hasNext()){
                CourseType type = iterator.next();
                //自己id为遍历出来的id
                if (owerCourseType.getId().intValue()==type.getId().intValue()){
                    iterator.remove();
                    break;
                }
            }
            node.put("otherCourseTypes",allChirdren);
            result.add(node);
        }

        return result;
    }


    @Override
    public List<CourseType> treeData(long pid) {

        //如果换成中有就直接返回
        List<CourseType>courseTypes = courseTypeCache.getTreeData();
        if (courseTypes!=null && courseTypes.size()>0){
            System.out.println("cache ....");
            return courseTypes;
        }else{
            System.out.println("db....");
            //否则先查询数据库，放入换成后再返回
            //递归思想 每一个节点都会发一天sql
            //return treeDataRecursion(pid);
            //循环方案 一条sql
            List<CourseType> courseTypesOfDb = treeDataLoop(pid);
            courseTypeCache.setTreeData(courseTypesOfDb);
            return courseTypesOfDb;
        }

    }


    //循环方案-一条sql自己组织关系
    private List<CourseType> treeDataLoop(long pid) {
        //1查询所有的节点
        List<CourseType> allNodes = courseTypeMapper.selectList(null);

        //为了查询父亲方便，我建立所有节点的一个key（Id）-vue（Node）集合 n
        Map<Long,CourseType>  allNodeDto = new HashMap<>();
        for (CourseType courseType : allNodes) {
            allNodeDto.put(courseType.getId(),courseType);
        }
        //2组织关系
        List<CourseType> result = new ArrayList<>();
        for (CourseType courseType : allNodes) { //n
            //2.1 如果是一级节点之间放入result
            if (courseType.getPid().intValue()==0) {
                result.add(courseType);
            }else{
                //2.2 不是一级节点要建立父子关系-把自己作为父亲一个儿子添加进去
                //2.2.1 获取父亲
                Long pidTmp = courseType.getPid(); //不能发sql
                //方案1：遍历获取父亲，效率低下 两层for n*N
                /*
                for (CourseType courseType1 : allNodes) {
                    if (courseType1.getId() == pidTmp) {
                        //获取到了父亲了。。。。
                    }
                }*/
                //方案2：提前建立id和node直接关系，直接获取 //2n
                CourseType parent = allNodeDto.get(pidTmp);
                //2.2.2 给父亲添加儿子（自己）
                parent.getChildren().add(courseType);

            }

        }
        return  result;
    }

    /**
     * 通过父id查询儿子，有儿子就设置为自己的儿子，没有就返回
     * 自己调用自己
     * //返回条件
     * @param pid
     * @return
     */

    private List<CourseType> treeDataRecursion(long pid) {
        //发一条sql
        List<CourseType> children = courseTypeMapper
                .selectList(new EntityWrapper<CourseType>().eq("pid", pid));
        //返回条件
        if (children==null || children.size()<1){
            return null;
        }
        for (CourseType child : children) {
            //自己调用自己
            List<CourseType> cTmp = treeDataRecursion(child.getId());
            child.setChildren(cTmp);
        }

        return children;

    }

    //重写增删改方法-同步缓存,重新生成静态页面
    @Override
    public boolean insert(CourseType entity) {

        courseTypeMapper.insert(entity);
        courseTypeCache.setTreeData(treeDataLoop(0));
        staticIndexPageInit(); //静态化课程主页
        return true;
    }

    @Override
    public boolean deleteById(Serializable id) {
        courseTypeMapper.deleteById(id);
        courseTypeCache.setTreeData(treeDataLoop(0));
        staticIndexPageInit();  //静态化课程主页
        return true;
    }

    @Override
    public boolean updateById(CourseType entity) {
        courseTypeMapper.updateById(entity);
        courseTypeCache.setTreeData(treeDataLoop(0));
        staticIndexPageInit();  //静态化课程主页
        return true;
    }
}
